package com.tanhua.server.service;


import com.alibaba.dubbo.config.annotation.Reference;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.tanhua.dubbo.server.api.UsersCountApi;
import com.tanhua.dubbo.server.pojo.ActiveUser;
import com.tanhua.dubbo.server.vo.UsersCountVo;
import com.tanhua.server.enums.AgeRangeEnum;
import com.tanhua.server.enums.AreaEnum;
import com.tanhua.server.enums.ProfessionEnum;
import com.tanhua.server.mapper.UserInfoMapper;
import com.tanhua.server.mapper.UserMapper;
import com.tanhua.server.pojo.Info;
import com.tanhua.server.pojo.User;
import com.tanhua.server.pojo.UserInfo;
import com.tanhua.server.vo.ActiveUsersVo;
import com.tanhua.server.vo.DistributionVo;
import org.apache.commons.collections4.CollectionUtils;
import org.joda.time.DateTime;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class UsersCountService {

    @Reference(version = "1.0.0")
    private UsersCountApi usersCountApi;

    @Autowired
    private UserMapper userMapper;

    public UsersCountVo queryInfo() {
        try {
            UsersCountVo usersCountVo = usersCountApi.select();
            //在此填充累计用户,今日新增用户,今日用户增长率
            LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
            //累计用户
            List<User> userList = userMapper.selectList(wrapper);
            Integer cumulativeUsers = userList.size();
            //今日新增用户
            SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
            String timeStr = new DateTime().toString("yyyyMMdd");
            Date date = sdf.parse(timeStr);
            Integer newUserToday = 0;//今日新增用户
            Integer newUserPassYesterday = 0;//昨日,今日新增总用户
            for (User user : userList) {
                if (user.getCreated().getTime() > (date.getTime() - 24 * 3600 * 1000)) {
                    newUserPassYesterday++;
                    if (user.getCreated().getTime() > date.getTime()) {
                        newUserToday++;
                    }
                }
            }
            //计算今日新增用户增长率
            int newUserYesterday = newUserPassYesterday - newUserToday;//昨日增长数
            Integer newUsersTodayRate = 0;
            if (newUserYesterday == 0) {
                newUsersTodayRate = (newUserToday - newUserYesterday) * 100;
            } else {
                newUsersTodayRate = (int)(((newUserToday - newUserYesterday) / (newUserYesterday * 1.0)) * 100);
            }
            usersCountVo.setCumulativeUsers(cumulativeUsers);
            usersCountVo.setNewUsersToday(newUserToday);
            usersCountVo.setNewUsersTodayRate(newUsersTodayRate);
            return usersCountVo;
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return null;
    }

    //查询操作
    // type  101:新增 102:活跃用户 103:次日留存率
    public ActiveUsersVo countUsers(Long startTime, Long endTime, String type) throws ParseException {
        ActiveUsersVo activeUsersVo = new ActiveUsersVo();
        Date startDate = new Date(startTime);
        Date endDate = new Date(endTime);
        switch (type) {
            case "101": {
                getActiveUsersVo101(activeUsersVo, startDate, endDate);
                break;
            }
            case "102": {
                getActiveUsersVo102(startTime, endTime, activeUsersVo);
                break;
            }
            case "103": {
                List<Info> infoList1 = new ArrayList<>();//今年
                List<Info> infoList2 = new ArrayList<>();//去年
                Map<String, List<?>> result1 = getActiveUsersVo101(activeUsersVo, startDate, endDate);
                Map<String, List<?>> result2 = getActiveUsersVo102(startTime, endTime, activeUsersVo);
                int sdMonthOfYear = new DateTime(startDate).getMonthOfYear();
                int size = result1.size() / 2;//获取集合长度,即跨了几个月份,(今年 + 去年)/2
                for (int i = 0; i < size; i++) {
                    //今年
                    int sum1 = result1.get((sdMonthOfYear + i) + "今年").size();
                    int count1 = getThisYearCount(result1, result2, sdMonthOfYear, "今年", i);
                    int rate1 = 0;
                    if (sum1 == 0) {
                        rate1 = count1;
                    } else {
                        rate1 = (int) (((count1 * 1.0) / sum1) * 100);//百分比
                    }
                    infoList1.add(new Info((sdMonthOfYear + i) + "月", rate1));
                    //去年
                    int sum2 = result1.get((sdMonthOfYear + i) + "去年").size();
                    int count2 = getThisYearCount(result1, result2, sdMonthOfYear, "去年", i);
                    int rate2 = 0;
                    if (sum2 == 0) {
                        rate2 = count2;
                    } else {
                        rate2 = (int) (((count2 * 1.0) / sum2) * 100);//百分比
                    }
                    infoList2.add(new Info((sdMonthOfYear + i) + "月", rate2));
                }
                activeUsersVo.setThisYear(infoList1);
                activeUsersVo.setLastYear(infoList2);
                break;
            }
            default:
                break;
        }
        return activeUsersVo;
    }

    private int getThisYearCount(Map<String, List<?>> result1, Map<String, List<?>> result2, int sdMonthOfYear, String suffix, int i) {
        //今年
        String key = sdMonthOfYear + i + suffix;
        List<User> list1 = (List<User>) result1.get(key);//注册用户集合
        List<ActiveUser> list2 = (List<ActiveUser>) result2.get(key);//活跃用户集合
        int count = 0;
        for (User user : list1) {
            long time1 = user.getCreated().getTime();//注册时间
            long time2 = user.getCreated().getTime() + 1000 * 3600 * 24;//注册第二天
            for (ActiveUser activeUser : list2) {
                long time = activeUser.getFirstLoginTime();
                //id相同且第一次登录时间介于: time1 time2
                if (user.getId().longValue() == activeUser.getUserId().longValue()) {
                    if (time > time1 && time < time2) {
                        count++;
                    }
                    break;
                }
            }
        }
        return count;
    }

    private Map<String, List<?>> getActiveUsersVo102(Long startTime, Long endTime, ActiveUsersVo activeUsersVo) throws ParseException {
        List<Info> infoList1 = new ArrayList<>();//今年
        List<Info> infoList2 = new ArrayList<>();//去年
        Map<String, List<?>> map = new HashMap<>();
        Date startDate = new Date(startTime);
        Date endDate = new Date(endTime);
        int sdMonthOfYear = new DateTime(startDate).getMonthOfYear();
        int edMonthOfYear = new DateTime(endDate).getMonthOfYear();
        if (sdMonthOfYear != edMonthOfYear) {
            //月数不相等
            //隔几个月,循环多少次
            for (int i = 0; i <= (edMonthOfYear - sdMonthOfYear); i++) {
                //获得第二个月的月首00:00时间
                String newTimeStr = new DateTime(startDate).plusMonths(i + 1).toString("yyyyMMdd");
                String substring = newTimeStr.substring(0, 6);//获取前缀: 202107
                SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
                Date date = sdf.parse(substring + "01");//2021-07-01
                Integer count1 = 0;
                Integer count2 = 0;
                List<ActiveUser> list1 = null;
                List<ActiveUser> list2 = null;
                if (i == 0) {
                    //首月残月条件(特殊: 20210613~20210701)
                    //今年
                    list1 = usersCountApi.usersCount(startTime, date.getTime());
                    count1 = list1.size();
                    //去年
                    Date date1 = new DateTime(startDate).plusYears(-1).toDate();
                    Date date2 = new DateTime(date).plusYears(-1).toDate();
                    list2 = usersCountApi.usersCount(date1.getTime(), date2.getTime());
                    count2 = list2.size();

                } else if (i < (edMonthOfYear - sdMonthOfYear)) {
                    //正常满月: 20210701~20210801
                    //今年
                    Date date1 = new DateTime(date).plusMonths(-1).toDate();
                    list1 = usersCountApi.usersCount(date1.getTime(), date.getTime());
                    count1 = list1.size();
                    //去年
                    Date date2 = new DateTime(date).plusMonths(-13).toDate();
                    Date date3 = new DateTime(date).plusYears(-1).toDate();
                    list2 = usersCountApi.usersCount(date2.getTime(), date3.getTime());
                    count2 = list2.size();
                } else if (i == (edMonthOfYear - sdMonthOfYear)) {
                    //最后尾月残月(特殊: 20210801~20210816)
                    //今年
                    Date date1 = new DateTime(date).plusMonths(-1).toDate();
                    list1 = usersCountApi.usersCount(date1.getTime(), endTime);
                    count1 = list1.size();
                    //去年
                    Date date2 = new DateTime(date).plusMonths(-13).toDate();
                    Date date3 = new DateTime(endDate).plusYears(-1).toDate();
                    list2 = usersCountApi.usersCount(date2.getTime(), date3.getTime());
                    count2 = list2.size();
                }
                infoList1.add(new Info((sdMonthOfYear + i) + "月", count1));
                infoList2.add(new Info((sdMonthOfYear + i) + "月", count2));
                map.put((sdMonthOfYear + i) + "今年", list1);
                map.put((sdMonthOfYear + i) + "去年", list2);
            }
        } else {
            //同一月
            //今年
            List<ActiveUser> list1 = usersCountApi.usersCount(startTime, endTime);
            Integer count1 = list1.size();
            //去年
            Date date1 = new DateTime(startDate).plusYears(-1).toDate();
            Date date2 = new DateTime(endDate).plusYears(-1).toDate();
            List<ActiveUser> list2 = usersCountApi.usersCount(date1.getTime(), date2.getTime());
            Integer count2 = list2.size();
            infoList1.add(new Info(sdMonthOfYear + "月", count1));
            infoList2.add(new Info(sdMonthOfYear + "月", count2));
            map.put(sdMonthOfYear + "今年", list1);
            map.put(sdMonthOfYear + "去年", list2);
        }
        activeUsersVo.setThisYear(infoList1);
        activeUsersVo.setLastYear(infoList2);
        return map;
    }

    private Map<String, List<?>> getActiveUsersVo101(ActiveUsersVo activeUsersVo, Date startDate, Date endDate) throws ParseException {
        List<Info> infoList1 = new ArrayList<>();//今年
        List<Info> infoList2 = new ArrayList<>();//去年
        Map<String, List<?>> map = new HashMap<>();
        //如果时间段跨月,进行分月计数
        int sdMonthOfYear = new DateTime(startDate).getMonthOfYear();
        int edMonthOfYear = new DateTime(endDate).getMonthOfYear();
        if (sdMonthOfYear != edMonthOfYear) {
            //月数不相等
            //隔几个月,循环多少次
            for (int i = 0; i <= (edMonthOfYear - sdMonthOfYear); i++) {
                //获得第二个月的月首00:00时间
                String newTimeStr = new DateTime(startDate).plusMonths(i + 1).toString("yyyyMMdd");
                String substring = newTimeStr.substring(0, 6);//获取前缀: 202107
                SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
                Date date = sdf.parse(substring + "01");//2021-07-01
                LambdaQueryWrapper<User> wrapper1 = new LambdaQueryWrapper<>();
                LambdaQueryWrapper<User> wrapper2 = new LambdaQueryWrapper<>();
                if (i == 0) {
                    //首月残月条件(特殊: 20210613~20210701)
                    //今年
                    wrapper1.gt(User::getCreated, startDate).lt(User::getCreated, date);
                    //去年
                    Date date1 = new DateTime(startDate).plusYears(-1).toDate();
                    Date date2 = new DateTime(date).plusYears(-1).toDate();
                    wrapper2.gt(User::getCreated, date1).lt(User::getCreated, date2);
                } else if (i < (edMonthOfYear - sdMonthOfYear)) {
                    //正常满月: 20210701~20210801
                    wrapper1.gt(User::getCreated, new DateTime(date).plusMonths(-1).toDate()).lt(User::getCreated, date);
                    //去年
                    wrapper2.gt(User::getCreated, new DateTime(date).plusMonths(-13).toDate()).lt(User::getCreated, new DateTime(date).plusYears(-1).toDate());
                } else if (i == (edMonthOfYear - sdMonthOfYear)) {
                    //最后尾月残月(特殊: 20210801~20210816)
                    wrapper1.gt(User::getCreated, new DateTime(date).plusMonths(-1).toDate()).lt(User::getCreated, endDate);
                    //去年
                    wrapper1.orderByAsc(User::getMobile);
                    wrapper2.gt(User::getCreated, new DateTime(date).plusMonths(-13).toDate()).lt(User::getCreated, new DateTime(endDate).plusYears(-1).toDate());
                }
                List<User> userList1 = userMapper.selectList(wrapper1);
                Integer count1 = userList1.size();
                List<User> userList2 = userMapper.selectList(wrapper2);
                Integer count2 = userList2.size();
                infoList1.add(new Info((sdMonthOfYear + i) + "月", count1));
                infoList2.add(new Info((sdMonthOfYear + i) + "月", count2));
                map.put((sdMonthOfYear + i) + "今年", userList1);
                map.put((sdMonthOfYear + i) + "去年", userList2);
            }

        } else {
            //同一月
            //今年
            LambdaQueryWrapper<User> wrapper1 = new LambdaQueryWrapper<>();
            wrapper1.gt(User::getCreated, startDate).lt(User::getCreated, endDate);
            //当前时间段内总的新增用户
            List<User> userList1 = userMapper.selectList(wrapper1);
            Integer count1 = userList1.size();
            infoList1.add(new Info(sdMonthOfYear + "", count1));
            //去年
            LambdaQueryWrapper<User> wrapper2 = new LambdaQueryWrapper<>();
            wrapper2.gt(User::getCreated, new DateTime(startDate).plusYears(-1).toDate()).lt(User::getCreated, new DateTime(endDate).plusYears(-1).toDate());
            List<User> userList2 = userMapper.selectList(wrapper2);
            Integer count2 = userList2.size();
            infoList2.add(new Info(sdMonthOfYear + "月", count2));
            map.put(sdMonthOfYear + "今年", userList1);
            map.put(sdMonthOfYear + "去年", userList2);
        }
        activeUsersVo.setThisYear(infoList1);
        activeUsersVo.setLastYear(infoList2);
        return map;
    }


    @Autowired
    private UserInfoMapper userInfoMapper;

    public DistributionVo userDistribution(Long startTime, Long endTime) {
        DistributionVo distributionVo = new DistributionVo();
        //1.查询改时间段内所有注册用户
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        wrapper.gt(User::getCreated, new Date(startTime)).lt(User::getCreated, new Date(endTime));
        List<User> userList = userMapper.selectList(wrapper);
        //2.查询userList中所有用户的详细信息
        //2.1 获取所有userId
        Set<Long> userIds = userList.stream().map(User::getId).collect(Collectors.toSet());
        LambdaQueryWrapper<UserInfo> queryWrapper = new LambdaQueryWrapper<>();
        if (CollectionUtils.isNotEmpty(userIds))
            queryWrapper.in(UserInfo::getUserId, userIds);
        List<UserInfo> userInfoList = userInfoMapper.selectList(queryWrapper);
        //性别分布
        Map<Boolean, List<UserInfo>> collect1 = userInfoList.stream().collect(Collectors.groupingBy(i -> i.getSex().getValue() == 1));
        List<Info> genderList = new ArrayList<>();
        int num1 = 0;
        try {
            num1 = collect1.get(true).size();
        } catch (Exception e) {
        }
        int num2 = 0;
        try {
            num2 = collect1.get(false).size();
        } catch (Exception e) {
        }
        genderList.add(new Info("男性用户", num1));
        genderList.add(new Info("女性用户", num2));
        distributionVo.setGenderDistribution(genderList);
        //职业分布
        ProfessionEnum[] professionEnums = ProfessionEnum.values();
        //所有行业表profession
        Set<String> professionSet = new HashSet<>();
        for (ProfessionEnum professionEnum : professionEnums) {
            String profession = professionEnum.getProfession();
            professionSet.add(profession);
        }
        List<Info> professionList = new ArrayList<>();
        for (String s : professionSet) {
            int size = 0;
            try {
                size = userInfoList.stream().collect(Collectors.groupingBy(i -> ProfessionEnum.getProfessionEnumByJob(i.getOccupation()).equals(s))).get(true).size();
            } catch (Exception e) {
            }
            professionList.add(new Info(s, size));
        }
        distributionVo.setIndustryDistribution(professionList);
        //年龄分布
        List<Info> ageList = new ArrayList<>();
        AgeRangeEnum[] ageRangeEnums = AgeRangeEnum.values();
        for (AgeRangeEnum ageRangeEnum : ageRangeEnums) {
            Map<Boolean, List<UserInfo>> collect = userInfoList.stream().collect(Collectors.groupingBy(i -> i.getAge() > ageRangeEnum.getMin() & i.getAge() <= ageRangeEnum.getMax()));
            int size = 0;
            try {
                size = collect.get(true).size();
            } catch (Exception e) {
            }
            ageList.add(new Info(ageRangeEnum.getDesc(), size));
        }
        distributionVo.setAgeDistribution(ageList);
        //省份分布
        List<Info> provinceList = new ArrayList<>();
        AreaEnum[] areaEnums = AreaEnum.values();
        HashSet<String> areaSet = new HashSet<>();
        for (AreaEnum area : areaEnums) {
            areaSet.add(area.getArea());
            Map<Boolean, List<UserInfo>> collect = userInfoList.stream().collect(Collectors.groupingBy(i -> i.getCity().equals(area.getProvince())));
            int size = 0;
            try {
                size = collect.get(true).size();
            } catch (Exception e) {
            }
            provinceList.add(new Info(area.getProvince(), size));
        }
        distributionVo.setLocalDistribution(provinceList);
        //地区分布
        List<Info> areaList = new ArrayList<>();
        for (String s : areaSet) {
            Map<Boolean, List<UserInfo>> collect = userInfoList.stream().collect(Collectors.groupingBy(i -> AreaEnum.getAreaByProvince(i.getCity()).equals(s)));
            int size = 0;
            try {
                size = collect.get(true).size();
            } catch (Exception e) {
            }
            areaList.add(new Info(s, size));
        }
        distributionVo.setLocalTotal(areaList);
        return distributionVo;
    }

}
